'''
The Truthtabler
2 February 2011

Notes:
    1.  Make it a windows app using wxPython.
    2.  Has buttons representing P, Q, AND, NOT, (, ), etc.
    3.  The statement is shown and updated at each button click
    4.  Has a GO button which will display the truthtable.  
'''

import wx
import wx.grid as gridlib

class MyFrame(wx.Frame):
    def __init__(self, parent, id, title):
        # Define the window
        wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(300, 250))
        #self.SetIcon(wx.Icon('seat.ico', wx.BITMAP_TYPE_ICO))
        self.SetBackgroundColour('#99CCFF')
                
        self.formula = False
        sizer = wx.BoxSizer(wx.VERTICAL)
        
        # Define text display
        self.display = wx.TextCtrl(self, -1, '',  style=wx.TE_RIGHT)
        sizer.Add(self.display, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 4)

        # Define the buttons
        gs = wx.GridSizer(4, 4, 3, 3)
        gs.AddMany([(wx.Button(self, 20, 'Clear'), 0, wx.EXPAND),
                        (wx.StaticText(self, -1, ''), 0, wx.EXPAND), # Blank this button
                        (wx.StaticText(self, 22, ''), 0, wx.EXPAND), # Blank this button
                        (wx.Button(self, 21, 'GO'), 0, wx.EXPAND),
                        (wx.Button(self, 1, 'P'), 0, wx.EXPAND),
                        (wx.Button(self, 2, 'Q'), 0, wx.EXPAND),
                        (wx.Button(self, 3, '('), 0, wx.EXPAND),
                        (wx.Button(self, 4, ')'), 0, wx.EXPAND),
                        (wx.Button(self, 5, 'AND'), 0, wx.EXPAND),
                        (wx.Button(self, 6, 'OR'), 0, wx.EXPAND),
                        (wx.Button(self, 7, 'NOT'), 0, wx.EXPAND),
                        (wx.Button(self, 8, 'IMPLIES'), 0, wx.EXPAND) ])

        sizer.Add(gs, 1, wx.EXPAND)

        self.SetSizer(sizer)
        self.Centre()

        # Bind events to the buttons
        self.Bind(wx.EVT_BUTTON, self.OnClear, id=20)
        self.Bind(wx.EVT_BUTTON, self.OnGo, id=21)
        self.Bind(wx.EVT_BUTTON, self.OnP, id=1)
        self.Bind(wx.EVT_BUTTON, self.OnQ, id=2)
        self.Bind(wx.EVT_BUTTON, self.OnLeft, id=3)
        self.Bind(wx.EVT_BUTTON, self.OnRight, id=4)
        self.Bind(wx.EVT_BUTTON, self.OnAnd, id=5)
        self.Bind(wx.EVT_BUTTON, self.OnOr, id=6)
        self.Bind(wx.EVT_BUTTON, self.OnNot, id=7)
        self.Bind(wx.EVT_BUTTON, self.OnImplies, id=8)

    # Define all the events
    def OnClear(self, event):
        self.display.Clear()

    def OnLeft(self, event):
        if self.formula:
            self.display.Clear()
            self.formula = False
        self.display.AppendText('( ')

    def OnRight(self, event):
        if self.formula:
            return
        self.display.AppendText(') ')

    def OnImplies(self, event):
        if self.formula:
            return
        self.display.AppendText('IMPLIES ')
        
    def OnAnd(self, event):
        if self.formula:
            self.display.Clear()
            self.formula = False
        self.display.AppendText('AND ')

    def OnOr(self, event):
        if self.formula:
            self.display.Clear()
            self.formula = False
        self.display.AppendText('OR ')

    def OnNot(self, event):
        if self.formula:
            self.display.Clear()
            self.formula = False
        self.display.AppendText('NOT ')

    def OnP(self, event):
        if self.formula:
            self.display.Clear()
            self.formula = False
        self.display.AppendText('P ')

    def OnQ(self, event):
        if self.formula:
            self.display.Clear()
            self.formula = False
        self.display.AppendText('Q ')
        
    def OnGo(self, event):
        if self.formula:
            return              
        formula = self.display.GetValue()
        self.formula = False
        statement_before = formula.split()
                
        # Error-checking. Is the statement valid?
        bracketstack = [] # Store all brackets in a stack to keep track of numbers
        memory = "xx" # Stores the previous item in the statement
        valid = False 
        count = 1 
           
        # Filters out (hopefully) EVERY invalid combination within statements
        
        FalsePairs = [
            "P", "P",
            "Q", "Q",
            "NOT", "NOT",
            "AND", "AND",
            "P", "NOT",
            "Q", "NOT",
            "OR", "OR",
            "IMPLIES", "IMPLIES",
            ")", "(",
            "(", ")",
            "P", "Q",
            "Q", "P",
            "AND", "OR",
            "OR", "AND",
            "AND", "IMPLIES",
            "IMPLIES", "AND",
            "OR", "IMPLIES",
            "IMPLIES", "OR",
            "(", "AND",
            "(", "OR",
            "(", "IMPLIES",
            "AND", ")",
            "OR", ")",
            "IMPLIES", ")"
        ]
        
        for item in statement_before:
            for counter in range(0,len(FalsePairs),2):
                
                if memory == FalsePairs[counter] and item == FalsePairs[counter + 1]:
                        valid = False
                                
                # Add a bracket to the stack
                elif item == "(":
                    bracketstack.append(1)
                    valid = True
                    
                # Remove a bracket from the stack
                elif item == ")" and len(bracketstack) > 0:
                    bracketstack.pop()
                 
                # Trying to take from an empty stack   
                elif item == ")" and len(bracketstack) == 0:
                    valid = False
                    
                else:
                    valid = True
                
                if valid == False: # Break instantly out of loop if invalid.
                    break
                
            if valid == False: # Break instantly out of loop if invalid.
                break
                
            memory = item # To remember what came prior.

        # Bracket stack should now be empty
        if len(bracketstack) > 0: 
            valid = False
        
        # Final results.
        
        if not valid: # Statement is invalid
            self.display.Clear()
            self.display.AppendText('INVALID STATEMENT')
        
        else: # Statement is valid.
            
            ###############################################################################################
            # Glen's part goes here. statement_before goes in. statement_after comes out.
            ###############################################################################################
            
            # temporary statement_after.
            statement_after = [["P", 1, 1, 0, 0],["Q", 1, 0, 1, 0],["P AND Q", 1, 0, 0, 0]]
            
            # pass frame1 to frame2 as instance self
            self.frame2 = Frame2(None, 'Truthtable', self, statement_after)
            self.Hide()
            self.frame2.Show()           

class Frame2(wx.Frame):
    def __init__(self, parent, mytitle, frame1, statement_after):
        wx.Frame.__init__(self, parent=None, title="py-Truthtable", size=(900, 170))
        panel = wx.Panel(self)
        
        ColNumber = len(statement_after)
 
        myGrid = gridlib.Grid(panel)
        myGrid.CreateGrid(4, ColNumber)
        myGrid.SetRowLabelSize(0)
        
        # Display column labels
        for item in range(ColNumber):
            myGrid.SetColLabelValue(item, statement_after[item][0])
            
        # Display grid contents
        for group in range(ColNumber):
            for item in range(4):
                myGrid.SetCellValue(item, group, str(statement_after[group][item+1]))
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(myGrid, 1, wx.EXPAND)
        panel.SetSizer(sizer)

class MyApp(wx.App):
    def OnInit(self):
        frame = MyFrame(None, -1, 'py-Truthtable.py')
        frame.Show(True)
        self.SetTopWindow(frame)
        return True

app = MyApp(0)
app.MainLoop()
